package com.example.spring_source_code.anno.bean;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Map;
import java.util.Set;

public class BeanPostProcessor {
    public static void main(String[] args) throws IOException {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config", Config.class);
        //1 获取config类上含有@Bean注解的方法
        ClassPathResource resource = new ClassPathResource("/com/example/spring_source_code/anno/bean/Config.class");
        CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
        MetadataReader metadataReader = readerFactory.getMetadataReader(resource);
        //2 判断@Bean注解中是否含有initMethod方法等.
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        Set<MethodMetadata> annotatedMethods = annotationMetadata.getAnnotatedMethods(Bean.class.getName());
        for (MethodMetadata method : annotatedMethods) {
            //3 生成beanDefinition对象
            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition()
                    .setFactoryMethod(method.getMethodName())
                    .setFactoryMethodOnBean(method.getMethodName(),"config")
                    .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR).getBeanDefinition();
            Map<String, Object> attributes = method.getAnnotationAttributes(Bean.class.getName());
            String initMethod = attributes.get("initMethod").toString();
            if (initMethod != null && !"".equals(initMethod)) {
                beanDefinition.setInitMethodName(initMethod);
            }
            //4 注入容器
            context.getDefaultListableBeanFactory().registerBeanDefinition(method.getMethodName(), beanDefinition);
        }

        context.refresh();

        for (String beanDefinitionName : context.getBeanDefinitionNames()) {
            System.out.println("beanDefinitionName = " + beanDefinitionName);
        }

    }
}
